package org.budo.dubbo.protocol.http.sign;

import java.net.InetSocketAddress;

import org.budo.dubbo.protocol.http.Consts;
import org.budo.dubbo.protocol.http.exception.remoting.ProviderSideRuntimeException;
import org.budo.dubbo.protocol.http.exception.remoting.SignCheckException;
import org.budo.dubbo.protocol.http.invocation.BudoDubboRpcInvocation;
import org.budo.dubbo.protocol.http.util.BudoBeanUtil;
import org.budo.dubbo.protocol.http.util.BudoReflectionUtil;

import com.alibaba.dubbo.rpc.Filter;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcContext;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.RpcResult;

/**
 * provider-side-sign
 * 
 * @author lmw
 * @see org.budo.dubbo.protocol.http.sign.SignCheck
 */
public class ProviderSideSignFilter implements Filter {
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        SignCheck signCheckAnnotation = BudoReflectionUtil.getMethodAnnotation(invoker.getInterface(), //
                invocation.getMethodName(), //
                invocation.getParameterTypes(), //
                SignCheck.class);

        if (null == signCheckAnnotation || !signCheckAnnotation.value()) {
            return invoker.invoke(invocation);
        }

        SignCheckService signCheckService = (SignCheckService) BudoBeanUtil.getBeanCached(SignCheckService.class, null);
        if (null == signCheckService) {
            String message = "#43 signCheckService required, this=" + this + ", applicationContext=" + BudoBeanUtil.getApplicationContext();
            throw new ProviderSideRuntimeException(message);
        }

        // 正常执行请求
        if (signCheckService.signCheck((BudoDubboRpcInvocation) invocation)) {
            return invoker.invoke(invocation);
        }

        InetSocketAddress remoteAddress = RpcContext.getContext().getRemoteAddress();
        String consumerSideSign = invocation.getAttachment(Consts.HeaderKey.Sign);

        String message = "#51 sign check error" //
                + ", remoteAddress=" + remoteAddress //
                + ", consumerSideSign=" + consumerSideSign //
                + ", providerInvocation=" + invocation //
                + ", signCheckService=" + signCheckService;

        Throwable exception = new SignCheckException(message, SignCheckException.Fail.SIGN_ERROR);
        return new RpcResult(exception); // 客户端异常
    }
}